package config

import (
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"log"
)

var Conf *Config

type Config struct {
	Log         LogConf                 `mapstructure:"log"`
	Port        int                     `mapstructure:"port"`
	WsPort      int                     `mapstructure:"wsPort"`
	MeticPort   int                     `mapstructure:"metricPort"`
	HttpPort    int                     `mapstructure:"httpPort"`
	AppName     string                  `mapstructure:"appName"`
	Database    Database                `mapstructure:"db"`
	Jwt         JwtConf                 `mapstructure:"jwt"`
	Grpc        GrpcConf                `mapstructure:"grpc"`
	Etcd        EtcdConf                `mapstructure:"etcd"`
	Domain      map[string]Domain       `mapstructure:"domain"`
	Services    map[string]ServicesConf `mapstructure:"services"`
	MySQLConfig MySQLConfig             `mapstructure:"mysql"`
}

type MySQLConfig struct {
	User            string `mapstructure:"user"`
	Password        string `mapstructure:"password"`
	DB              string `mapstructure:"db"`
	Host            string `mapstructure:"host"`
	Port            int    `mapstructure:"port"`
	MaxOpenConns    int    `mapstructure:"max_open_conns"`
	MaxIdleConns    int    `mapstructure:"max_idle_conns"`
	ConnMaxLifeTime int    `mapstructure:"conn_max_life_time"`
}

type ServicesConf struct {
	Id         string `mapstructure:"id"`
	ClientHost string `mapstructure:"clientHost"`
	ClientPort int    `mapstructure:"clientPort"`
}

type Domain struct {
	Name        string `mapstructure:"name"`
	LoadBalance bool   `mapstructure:"loadBalance"`
}

type Database struct {
	MongoConf MongoConf `mapstructure:"mongo"`
	RedisConf RedisConf `mapstructure:"redis"`
}

type MongoConf struct {
	Url         string `mapstructure:"url"`
	Db          string `mapstructure:"db"`
	Username    string `mapstructure:"username"`
	Password    string `mapstructure:"password"`
	MinPoolSize int    `mapstructure:"minPoolSize"`
	MaxPoolSize int    `mapstructure:"maxPoolSize"`
}

type RedisConf struct {
	Addr         string   `mapstructure:"addr"`
	ClusterAddrs []string `mapstructure:"clusterAddrs"`
	Password     string   `mapstructure:"password"`
	PoolSize     int      `mapstructure:"poolSize"`
	MinIdleConns int      `mapstructure:"minIdleConns"`
	Host         string   `mapstructure:"host"`
	Port         int      `mapstructure:"port"`
}

type JwtConf struct {
	Secret string `mapstructure:"secret"`
	Exp    int64  `mapstructure:"exp"`
}

type GrpcConf struct {
	Addr string `mapstructure:"addr"`
}

type EtcdConf struct {
	Addrs       []string       `mapstructure:"addrs"`
	RWTimeout   int            `mapstructure:"rwTimeout"`
	DialTimeout int            `mapstructure:"dialTimeout"`
	Register    RegisterServer `mapstructure:"register"`
}

type RegisterServer struct {
	Addr    string `mapstructure:"addr"`
	Name    string `mapstructure:"name"`
	Version string `mapstructure:"version"`
	Weight  int    `mapstructure:"weight"`
	Ttl     int64  `mapstructure:"ttl"`
}

type LogConf struct {
	Level string `mapstructure:"level"`
}

func InitConfig(confFile *string) {
	Conf = new(Config)
	v := viper.New()
	v.SetConfigFile(*confFile)
	v.WatchConfig()
	v.OnConfigChange(func(in fsnotify.Event) {
		log.Println("change config file")
		unmarshallConfig(v)
	})

	if err := v.ReadInConfig(); err != nil {
		panic(fmt.Errorf("Fatal error read config file: %s \n", err))
		return
	}

	unmarshallConfig(v)
}

func unmarshallConfig(v *viper.Viper) {
	if err := v.Unmarshal(&Conf); err != nil {
		panic(fmt.Errorf("Fatal error unmarshall config file: %s \n", err))
		return
	}
}
